Shader "volumeFogVF3"
{
Properties
{
	_FogColor ("Fog Color", Color) = (0, 0.15, 0.115, 1)
    _FogDensity ("FogDensity", Range(0,0.1)) = 0.03
    _Threshold ("Threshold", Range(0, 20)) = 5
    _Samples ("_Samples", Range(1, 40)) = 40
}
SubShader
{
	Tags { "Queue" = "Transparent" "RenderType"="Transparent"}

	Blend  SrcAlpha OneMinusSrcAlpha

    Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

sampler2D _CameraDepthTexture;

struct v2f
{
    float4 vertex : SV_POSITION;
    float2 uv : TEXCOORD0;
    float3 viewVec : TEXCOORD1;
    float4 scrPos : TEXCOORD2;
    float4 worldPos : TEXCOORD3;
};

fixed4 _FogColor;
float _FogDensity;
float _Threshold;
float _Samples;

float4x4 _InverseProjectionMatrix;
float4x4 _InverseViewMatrix;

v2f vert (appdata_full v)
{
	v2f o;
    o.vertex =UnityObjectToClipPos(v.vertex);
	o.scrPos = ComputeGrabScreenPos(o.vertex);

    // NDC position
    float4 ndcPos = (o.scrPos / o.scrPos.w) * 2 - 1;

    // View space vector from near plane pointing to far plane
    o.viewVec = float3(unity_OrthoParams.xy * ndcPos.xy, 0);


    o.worldPos = mul(unity_ObjectToWorld, v.vertex);

    return o;
}

float  cloudRayMarching(float3 rayPos, float3 rayDir, float2 rayToContainerInfo)
//  rayToContainerInfo 长方体相交信息         
{
    // if (dstLimit <= 0) 
    //     return 0;

    float distanceToStart = rayToContainerInfo.x;
    float OverallDistance = -abs(rayToContainerInfo.y - rayToContainerInfo.x);

    int Samples = min(_Samples, 40) ; // 40 will be the maximum samples, you can change this value if needed

    //用OverallDistance来计算Distance来作为步进长度
    float Distance = OverallDistance / Samples;

    float samplePerDirStep = 5;
    float samplePerDirStepInv = 1 / samplePerDirStep;

    float sum = 0;
    float3 startPos = rayPos + rayDir * rayToContainerInfo.x;
    float currT = rayToContainerInfo.x;
    float _Threshold = 5;

    float3 rayDirPerStep = rayDir * samplePerDirStepInv;

    for(int i=1; i < 100; i++){

        startPos += rayDir;
        currT += samplePerDirStepInv;

        if(currT > rayToContainerInfo.y)
            return sum;

        // if( -_Threshold < startPos.x  && startPos.x < _Threshold &&  
        //  -_Threshold < startPos.y  && startPos.y < _Threshold &&  
        //   -_Threshold < startPos.z  && startPos.z < _Threshold )
        sum += _FogDensity;
    }

    return sum;
}

//边界框最小值       边界框最大值         
// float2 rayBoxDst(float3 boundsMin, float3 boundsMax, 
//             //世界相机位置      光线方向倒数
//             float3 rayOrigin, float3 invRaydir) 
// {
// float3 t0 = (boundsMin - rayOrigin) * invRaydir;
// float3 t1 = (boundsMax - rayOrigin) * invRaydir;
// float3 tmin = min(t0, t1);
// float3 tmax = max(t0, t1);

// float dstA = max(max(tmin.x, tmin.y), tmin.z); //进入点
// float dstB = min(tmax.x, min(tmax.y, tmax.z)); //出去点

// float dstToBox = max(0, dstA);
// float dstInsideBox = max(0, dstB - dstToBox);
// return float2(dstToBox, dstInsideBox);
// }


////https://gamedev.stackexchange.com/a/18459/147473
float2 rayBoxDst(float3 boundsMin, float3 boundsMax, 
                //世界相机位置      光线方向倒数
                float3 rayOrigin, float3 invRaydir) 
{
    float t1 = (boundsMin.x - rayOrigin.x)*invRaydir.x;
    float t2 = (boundsMax.x - rayOrigin.x)*invRaydir.x;
    float t3 = (boundsMin.y - rayOrigin.y)*invRaydir.y;
    float t4 = (boundsMax.y - rayOrigin.y)*invRaydir.y;
    float t5 = (boundsMin.z - rayOrigin.z)*invRaydir.z;
    float t6 = (boundsMax.z - rayOrigin.z)*invRaydir.z;

    float tmin = max(max(min(t1, t2), min(t3, t4)), min(t5, t6));
    float tmax = min(min(max(t1, t2), max(t3, t4)), max(t5, t6));

    return float2(tmin, tmax);
}

//计算世界空间坐标
// float4 GetWorldSpacePosition(float depth, float2 uv)
// {
//      // 屏幕空间 --> 视锥空间
//      float4 view_vector = mul(_InverseProjectionMatrix, float4(2.0 * uv - 1.0, depth, 1.0));
//      view_vector.xyz /= view_vector.w;
//      //视锥空间 --> 世界空间
//      float4x4 l_matViewInv = _InverseViewMatrix;
//      float4 world_vector = mul(l_matViewInv, float4(view_vector.xyz, 1));
//      return world_vector;
// }

fixed4 frag (v2f i) : SV_Target
{

    float near = _ProjectionParams.y;
    float far = _ProjectionParams.z;

    // Sample the depth texture to get the linear depth
    float rawDepth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, i.scrPos));
    float ortho = (far - near) * (1 - rawDepth) + near;
    float depth = lerp(LinearEyeDepth(rawDepth), ortho, unity_OrthoParams.w) / far;

    // Linear interpolate between near plane and far plane by depth value
    float z = -lerp(near, far, depth);

    // View space position
    float3 viewPos = float3(i.viewVec.xy, z);

    // Pixel world position
    float3 depthWorldPos = mul(UNITY_MATRIX_I_V, float4(viewPos, 1)).xyz;

    return fixed4(depthWorldPos, 1);

    float3 mWorldPos = i.worldPos;

    //return fixed4(worldPos, 0.5);

    float3 rayPos = _WorldSpaceCameraPos;

    //世界空间相机方向
    float3 worldViewDir = normalize(mWorldPos.xyz - rayPos.xyz) ;

    float3 _boundsMin = float3(-_Threshold,-_Threshold, -_Threshold);
    float3 _boundsMax = float3(_Threshold, _Threshold, _Threshold);

    //float depthEyeLinear = length(worldPos.xyz - _WorldSpaceCameraPos);  
    float3 invRaydir = (1 / worldViewDir);
    float2 rayToContainerInfo = rayBoxDst(_boundsMin, _boundsMax, rayPos, invRaydir);
    // float dstToBox = rayToContainerInfo.x; //相机到容器的距离
    // float dstInsideBox = rayToContainerInfo.y; //返回光线是否在容器中
    //相机到物体的距离 - 相机到容器的距离，这里跟 光线是否在容器中 取最小，过滤掉一些无效值
    //float dstLimit = min(depthEyeLinear - dstToBox, dstInsideBox);

    //return fixed4(worldViewDir, 1);


    float dstLimit = min( (depthWorldPos - rayPos) * invRaydir , rayToContainerInfo.y);
    rayToContainerInfo.y = dstLimit;

    float FogDensity = cloudRayMarching(rayPos, worldViewDir, rayToContainerInfo);

    return fixed4(FogDensity * fixed3(1,1,1), 1);
    return _FogColor * FogDensity;
}

ENDCG
    }
}
    FallBack off
}